package com.gutai.admin.common.util;

import java.lang.reflect.Field;
import java.util.Date;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Map.Entry;
import java.util.Set;
import java.util.stream.Collectors;

import javax.persistence.Id;
import javax.persistence.Table;

import org.apache.commons.lang3.StringUtils;

import com.gutai.admin.entity.Category;

/**
 * 
 * 描述：
 * 
 * <pre>
 * HISTORY
 * ****************************************************************************
 *  ID    DATE            PERSON            REASON
 *  1     2018年11月20日         YC           Create
 * ****************************************************************************
 * </pre>
 * 
 * @author YC
 * @version 1.0
 */
public class JdbcTempleMapperUtil {

    private JdbcTempleMapperUtil() {
        // TODO 自动生成的构造函数存根
    }

    private static JdbcTempleMapperUtil instance = new JdbcTempleMapperUtil();

    public static final int INSERT = 0;
    public static final int UPDATE = 1;
    public static final int DELETE = 2;
    public static final int QUERY  = 3;
    public static final int QUERY_ALL = 4;

    private static final String INSERT_FORMAT = "insert into %s(%s) values(%s);";
    private static final String UPDATE_FORMAT = "update %s SET %s WHERE %s=%s;";
    private static final String DELETE_FORMAT = "delete from %s WHERE 1=1 %s;";
    private static final String QUERY_FORMAT = "select %s from %s WHERE 1=1 %s ";
    private static final String QUERY_ALL_FORMAT = "select * from %s ";

    private static final char UNDERLINE = '_';

    /**
     * 转换sql语句
     * 
     * @param sqlType
     * @param objs
     * @return
     * @author YC-2018年11月20日
     */
    public static String convertSqlByType(int sqlType, Object... objs) {
        String sql = "";
        switch (sqlType) {
            case INSERT:
                if (objs.length == 3) {
                    sql = String.format(INSERT_FORMAT, objs);
                }
                break;
            case UPDATE:
                if (objs.length == 4) {
                    sql = String.format(UPDATE_FORMAT, objs);
                }
                break;
            case DELETE:
                if (objs.length == 2) {
                    sql = String.format(DELETE_FORMAT, objs);
                }
                break;
            case QUERY:
                if (objs.length == 3) {
                    sql = String.format(QUERY_FORMAT, objs);
                }
                break;
            case QUERY_ALL:
                if (objs.length == 1) {
                    sql = String.format(QUERY_ALL_FORMAT, objs);
                }
                break;
        }
        return sql;
    }

    /**
     * 转换对象的属性名成表的列名：大写字母变下划线
     * 
     * @param tableColumn
     * @return
     * @author YC-2018年11月20日
     */
    private String transColumnName(String tableColumn) {
        StringBuilder sb = new StringBuilder(tableColumn);
        int tmp = 0;
        for (int i = 0; i < tableColumn.length(); i++) {
            if (Character.isUpperCase(tableColumn.charAt(i))) {
                sb.insert(i + tmp, UNDERLINE);
                tmp++;
            }
        }
        return sb.toString().toLowerCase();
    }

    /**
     * 获取对象的对应的表名
     * 
     * @param entity
     * @return
     * @author YC-2018年11月20日
     */
    private <T> String getTableName(T entity) {
        Class cls = entity.getClass();
        return getTableName(cls);
    }

    /**
     * 获取对象的对应的表名
     * 
     * @param entity
     * @return
     * @author YC-2018年11月20日
     */
    private <T> String getTableName(Class<T> clazz) {
        return ((Table) clazz.getAnnotation(Table.class)).name();
    }

    /**
     * 获取对象的对应表的主键
     * 
     * @param entity
     * @return
     * @author LA.01367604-2018年11月21日
     */
    private <T> Field getTableId(T entity) {
        Class cls = entity.getClass();
        return getTableId(cls);
    }

    /**
     * 获取对象的对应表的主键属性
     * 
     * @param entity
     * @return
     * @author LA.01367604-2018年11月21日
     */
    private <T> Field getTableId(Class<T> clazz) {
        List<Field> fields = AnnotationUtil.getFields(clazz, Id.class);
        if (CollectionUtil.isNotEmpty(fields)) {
            return fields.get(0);
        }
        return null;
    }

    // ******************** 对外提供的工具方法 *****************************

    /**
     * 获取对象的各个属性的名称和值
     * 
     * @param entity
     * @return
     * @author YC-2018年11月20日
     */
    public static <T> Map<String, Object> getAllFeilds(T entity) {
        Class cls = entity.getClass();
        Field[] fields = cls.getDeclaredFields();// 得到所有属性
        Map<String, Object> feildMap = new HashMap<>();
        for (int i = 0; i < fields.length; i++) {
            getValueByFieldName(fields[i], entity, feildMap);
        }
        return feildMap;
    }

    /**
     * 获取对象属性值非空的属性名称和值
     * 
     * @param field
     * @param obj
     * @author LA.01367604-2019年2月15日
     */
    public static Object getValueByFieldName(Field field, Object obj) {
        try {
            if (field != null && obj != null) {
                field.setAccessible(true);// 打开私有访问
                return field.get(obj);// 获取属性值
            }
        } catch (IllegalAccessException e) {
            e.printStackTrace();
        }
        return null;
    }

    /**
     * 获取对象属性值非空的属性名称和值
     * 
     * @param field
     * @param obj
     * @param feildMap
     * @author LA.01367604-2018年11月21日
     */
    public static void getValueByFieldName(Field field, Object obj, Map<String, Object> feildMap) {
        Object value = getValueByFieldName(field, obj);
        String name = field.getName();// 获取属性
        if (value != null) {
            feildMap.put(name, getValueWithFormat(obj.getClass().getTypeName(), value));
        }
    }
    
    /**
     * 获取格式化的属性值：添加单引号，格式化date时间
     * 
     * @param valueTypeName
     * @param value
     * @return
     * @author YC-2018年12月30日
     */
    public static String getValueWithFormat(String valueTypeName, Object value){
        String valueFormated = String.valueOf(value);
        if ("java.util.Date".equals(valueTypeName)
                || "java.sql.Timestamp".equals(valueTypeName)) {
            valueFormated = "'" + DateUtil.date2String((Date) value) + "'";
        } else if ("java.util.Integer".equals(valueTypeName)
                || "java.util.int".equals(valueTypeName)
                || "java.util.short".equals(valueTypeName)
                || "java.util.Long".equals(valueTypeName)
                || "java.util.long".equals(valueTypeName)
                || "java.util.Double".equals(valueTypeName)
                || "java.util.double".equals(valueTypeName)
                || "java.util.Short".equals(valueTypeName)) {
            valueFormated = String.valueOf(value);
        } else {
            valueFormated = "'" + valueFormated + "'";
        }
        return valueFormated;
    }

    /**
     * 获取对象的主键值
     * 
     * @param elem
     * @return
     * @author LA.01367604-2019年2月15日
     */
    public static <T> Integer getIdValue(T elem) {
        Field field = instance.getTableId(elem);
        Object value = getValueByFieldName(field, elem);
        if (value != null) {
            return Integer.valueOf((String) value);
        }
        return null;
    }

    // ******************** 构造生成SQL语句方法 *****************************

    /**
     * 生成插入sql语句
     * 
     * @param entity
     * @return
     * @author YC-2018年11月20日
     */
    public static <T> String covertInsertSql(T entity) {
        Map<String, Object> feildMap = getAllFeilds(entity);
        StringBuilder attrNames = new StringBuilder();
        StringBuilder attrValues = new StringBuilder();
        for (Entry<String, Object> entry : feildMap.entrySet()) {
            attrNames.append(instance.transColumnName(entry.getKey())).append(",");
            attrValues.append(entry.getValue()).append(",");
        }
        attrNames.deleteCharAt(attrNames.length() - 1); // 删除最后的逗号
        attrValues.deleteCharAt(attrValues.length() - 1); // 删除最后的逗号
        String tableName = instance.getTableName(entity);
        if (StringUtils.isNotEmpty(tableName) && StringUtils.isNotEmpty(attrNames.toString())&& StringUtils.isNotEmpty(attrValues.toString())){
            return convertSqlByType(INSERT, tableName, attrNames.toString(), attrValues.toString());
        }
        return null;
    }

    /**
     * 生成更新sql语句
     * 
     * @param entity
     * @return
     * @author LA.01367604-2018年11月21日
     * @throws Exception
     */
    public static <T> String covertUpdateSql(T entity){
        Map<String, Object> fieldMap = getAllFeilds(entity);
        StringBuilder nameAndValues = new StringBuilder();
        for (Entry<String, Object> entry : fieldMap.entrySet()) {
            nameAndValues.append(instance.transColumnName(entry.getKey())).append("=").append(entry.getValue()).append(",");
        }
        nameAndValues.deleteCharAt(nameAndValues.length() - 1); // 删除最后的逗号
        String tableName = instance.getTableName(entity);
        Field tableIdField = instance.getTableId(entity);
        if (StringUtils.isNotEmpty(tableName) && tableIdField!=null && StringUtils.isNotEmpty(nameAndValues.toString())){
            return convertSqlByType(UPDATE, tableName, nameAndValues.toString(), tableIdField.getName(), fieldMap.get(tableIdField.getName()));
        }
        return null;
    }

    /**
     * 生成条件删除sql语句
     * 
     * @param entity
     * @return
     * @author LA.01367604-2018年11月21日
     */
    public static <T> String covertDeleteSql(Class<T> clazz, Map<String, Object> whereFieldsMap) {
        String tableName = instance.getTableName(clazz);
        if (StringUtils.isNotEmpty(tableName) && whereFieldsMap!=null) {
            String nameAndValues = wrapWhereField(whereFieldsMap);
            return convertSqlByType(DELETE, tableName, nameAndValues);
        }
        return null;
    }
    /**
     * 生成主键删除sql语句
     * 
     * @param entity
     * @return
     * @author LA.01367604-2018年11月21日
     */
    public static <T> String covertDeleteSql(Class<T> clazz, int idValue) {
        String tableName = instance.getTableName(clazz);
        Field tableIdField = instance.getTableId(clazz);
        if (StringUtils.isNotEmpty(tableName) && tableIdField != null) {
            return convertSqlByType(DELETE, tableName, tableIdField.getName(), idValue);
        }
        return null;
    }
    
    /**
     * 生成条件查询sql语句
     * @param clazz
     * @param filterFields 过滤查询的字段
     * @param whereFieldsMap <字段名，字段值>查询条件
     * @return
     * @author LA.01367604-2018年11月21日
     */
    public static <T> String covertSelectSql(Class<T> clazz, Set<String> filterFields, Map<String,Object> whereFieldsMap){
        String tableName = instance.getTableName(clazz);
        if (StringUtils.isNotEmpty(tableName)) {
            String nameAndValues = wrapWhereField(whereFieldsMap);
            String selectFields = "*";
            if (CollectionUtil.isNotEmpty(filterFields)) {
                selectFields = filterFields.stream().collect(Collectors.joining(","));
            }
            return convertSqlByType(QUERY, selectFields, tableName, nameAndValues);
        }
        return null;
    }
    
    /**
     * 转换查询条件map成SQL语句的WHERE条件
     * @param whereFieldsMap
     * @return
     * @author LA.01367604-2019年2月15日
     */
    private static String wrapWhereField(Map<String,Object> whereFieldsMap){
        StringBuilder nameAndValues = new StringBuilder();
        for (Entry<String, Object> entry : whereFieldsMap.entrySet()) {
            nameAndValues.append(" and ").append(instance.transColumnName(entry.getKey()));
            String valueStr = String.valueOf(entry.getValue());
            if (valueStr.startsWith(">") || valueStr.startsWith("<")){
                nameAndValues.append(valueStr);
            } else {
                nameAndValues.append("=").append(getValueWithFormat(entry.getValue().getClass().getTypeName(),entry.getValue()));
            }
        }
        return nameAndValues.toString();
    }
    
    /**
     * 生成条件查询sql语句
     * 
     * @param clazz
     * @param filterFields
     * @param whereFieldsMap
     * @return
     * @author la.01367604-2019年1月25日
     */
    public static <T> String covertSelectSql(Class<T> clazz, Map<String, Object> whereFieldsMap) {
        return covertSelectSql(clazz, null, whereFieldsMap);
    }
    
    /**
     * 生成条件查询sql语句(mysql分页)
     * 
     * @param clazz
     * @param fieldsMap
     * @param pageIdx
     * @param pageNum
     * @return
     * @author la.01367604-2019年1月22日
     */
    public static <T> String covertSelectSql(Class<T> clazz, Set<String> filterFields, Map<String,Object> whereFieldsMap, int pageIdx, int pageNum){
        String sqlStr = covertSelectSql(clazz,filterFields, whereFieldsMap);
        return covertSelectByPage(sqlStr, pageIdx, pageNum);
    }
    /**
     * 生成主键查询sql语句
     * @param clazz
     * @param idValue
     * @return
     * @author LA.01367604-2018年11月21日
     */
    public static <T> String covertSelectSql(Class<T> clazz, int idValue) {
        Field tableIdField = instance.getTableId(clazz);
        if (tableIdField != null) {
            Map<String, Object> whereFields = new HashMap<>();
            whereFields.put(tableIdField.getName(), idValue);
            return covertSelectSql(clazz, null, whereFields);
        }
        return null;
    }

    /**
     * 生成全表查询sql语句
     * 
     * @param clazz
     * @return
     * @author LA.01367604-2018年11月21日
     */
    public static <T> String covertSelectAllSql(Class<T> clazz) {
        String tableName = instance.getTableName(clazz);
        if (StringUtils.isNotEmpty(tableName)) {
            return convertSqlByType(QUERY_ALL, tableName);
        }
        return null;
    }

    /**
     * 生成全表查询sql语句(mysql分页)
     * 
     * @param clazz
     * @param pageIdx
     * @param pageNum
     * @return
     * @author la.01367604-2019年1月22日
     */
    public static <T> String covertSelectAllSql(Class<T> clazz, int pageIdx, int pageNum) {
        String sqlStr = covertSelectAllSql(clazz);
        return covertSelectByPage(sqlStr, pageIdx, pageNum);
    }

    /**
     * 分页查询处理
     * 
     * @param sqlStr
     * @param pageIdx
     * @param pageNum
     * @return
     * @author la.01367604-2019年1月22日
     */
    public static <T> String covertSelectByPage(String sqlStr, int pageIdx, int pageNum) {
        if (StringUtils.isNotEmpty(sqlStr)) {
            // 查询第page页的数据sql语句
            if (pageIdx <= 1) {
                sqlStr += " limit 0," + pageNum;
            } else {
                sqlStr += " limit " + ((pageIdx - 1) * pageNum) + "," + pageNum;
            }
            return sqlStr;
        }
        return null;
    }

    public static void main(String[] args) {
        // String source = "abcABC";
        // JdbcTempleMapperUtil jdbc = new JdbcTempleMapperUtil();
        // System.out.println(jdbc.transColumnName(source));
        // source = "abc";
        // System.out.println(jdbc.transColumnName(source));
        // source = "ABC";
        // System.out.println(jdbc.transColumnName(source));
        Category category = new Category();
        category.setId(1);
        category.setName("A");

        String sql = covertInsertSql(category);
        System.out.println(sql);
        sql = covertUpdateSql(category);
        System.out.println(sql);
        Map<String, Object> map = new HashMap<>();
        map.put("name", "饮食");
        // map.put("name", "饮食");
        sql = covertSelectSql(Category.class, map);
        System.out.println(sql);
    }

}
